﻿Option Explicit On
Option Strict On

Imports ACOMDirector
Imports System
Imports System.ComponentModel
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms
Imports System.Diagnostics

''' <summary>
''' User control to mimick an LED
''' </summary>
''' <remarks></remarks>
Public Class LedBulb
    Inherits Control

#Region " Private Members "

    Private m_DarkColor As Color
    Private m_DarkDarkColor As Color
    Private m_Color As Color
    Private m_On As Boolean
    Private m_State As ACOMDirector.Framework.Hardware.LedStatus

    Private WithEvents m_BlinkTimer As New Windows.Forms.Timer

#End Region

#Region " Constructor "

    ''' <summary>
    ''' Default Constructor
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub New()
        SetStyle(ControlStyles.SupportsTransparentBackColor, True)
        Color = Color.FromArgb(255, 153, 255, 54)
        m_BlinkTimer.Interval = 100
        m_BlinkTimer.Enabled = False
    End Sub

#End Region

#Region " Public Properties "

    Protected Overrides ReadOnly Property CreateParams As System.Windows.Forms.CreateParams
        <System.Security.Permissions.SecurityPermission(Security.Permissions.SecurityAction.LinkDemand, flags:=Security.Permissions.SecurityPermissionFlag.UnmanagedCode)> _
        Get
            Dim params As CreateParams = MyBase.CreateParams
            params.ExStyle = params.ExStyle Or &H20
            Return params
        End Get
    End Property

    ''' <summary>
    ''' Gets or Sets the color of the LED light
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    <DefaultValue(GetType(Color), "153, 255, 54")> _
    Public Property Color As Color
        Get
            Return m_Color
        End Get
        Set(ByVal value As Color)
            m_Color = value
            DarkColor = ControlPaint.Dark(m_Color)
            DarkDarkColor = ControlPaint.DarkDark(m_Color)
            Me.Invalidate() ' Redraw the control
        End Set
    End Property

    ''' <summary>
    ''' Dark shade of the LED color used for gradient
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property DarkColor As Color
        Get
            Return m_DarkColor
        End Get
        Set(value As Color)
            m_DarkColor = value
        End Set
    End Property

    ''' <summary>
    ''' Very dark shade of the LED color used for gradient
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property DarkDarkColor As Color
        Get
            Return m_DarkDarkColor
        End Get
        Set(value As Color)
            m_DarkDarkColor = value
        End Set
    End Property

    ''' <summary>
    ''' The state of the LED
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property State As ACOMDirector.Framework.Hardware.LedStatus
        Get
            Return m_State
        End Get
        Set(ByVal value As ACOMDirector.Framework.Hardware.LedStatus)
            m_State = value
            Select Case m_State
                Case Framework.Hardware.LedStatus.On
                    m_On = True
                    m_BlinkTimer.Enabled = False
                    Me.Invalidate()
                Case Framework.Hardware.LedStatus.Off
                    m_On = False
                    m_BlinkTimer.Enabled = False
                    Me.Invalidate()
                Case Framework.Hardware.LedStatus.Blinking
                    m_BlinkTimer.Enabled = True
            End Select
        End Set
    End Property

#End Region

#Region " Private Methods "

    Protected Overrides Sub OnMove(ByVal e As System.EventArgs)
        RecreateHandle()
    End Sub

    ''' <summary>
    ''' Handles the Paint event for this UserControl
    ''' </summary>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)

        'Validate Parameters
        If e Is Nothing Then
            Throw New ArgumentNullException("e")
        End If

        ' Create an offscreen graphics object for double buffering
        Using offScreenBmp As Bitmap = New Bitmap(Me.ClientRectangle.Width, Me.ClientRectangle.Height)
            Using g As System.Drawing.Graphics = Graphics.FromImage(offScreenBmp)
                g.SmoothingMode = SmoothingMode.HighQuality
                ' Draw the control
                drawControl(g)
                ' Draw the image to the screen
                e.Graphics.DrawImageUnscaled(offScreenBmp, 0, 0)
            End Using
        End Using

    End Sub

    ''' <summary>
    ''' Renders the control to an image
    ''' </summary>
    ''' <param name="g"></param>
    ''' <remarks></remarks>
    Private Sub drawControl(ByVal g As Graphics)

        'Validate Parameters
        If g Is Nothing Then
            Throw New ArgumentNullException("g")
        End If

        Dim lightColor As Color = CType(IIf((m_On), ControlPaint.Light(Me.Color), Me.DarkColor), Color)
        Dim darkColor As Color = CType(IIf((m_On), Me.Color, Me.DarkDarkColor), Color)

        Dim paddedRectangle As Rectangle = New Rectangle(Me.Padding.Left, Me.Padding.Top, Me.Width - (Me.Padding.Left + Me.Padding.Right), Me.Height - (Me.Padding.Top + Me.Padding.Bottom))
        paddedRectangle.Width -= 1
        paddedRectangle.Height -= 1
        Dim width As Integer = CInt(IIf((paddedRectangle.Width < paddedRectangle.Height), paddedRectangle.Width, paddedRectangle.Height))
        Dim drawRectangle As Rectangle = New Rectangle(paddedRectangle.X, paddedRectangle.Y, width, width)

        ' Draw the background ellipse
        If (drawRectangle.Width < 1) Then drawRectangle.Width = 1
        If (drawRectangle.Height < 1) Then drawRectangle.Height = 1
        Using Brush As New SolidBrush(darkColor)
            g.FillEllipse(Brush, drawRectangle)
        End Using

        ' Draw the glow gradient
        Using path As GraphicsPath = New GraphicsPath()
            path.AddEllipse(drawRectangle)
            Using pathBrush As PathGradientBrush = New PathGradientBrush(path)
                pathBrush.CenterColor = lightColor
                pathBrush.SurroundColors = New Color() {Color.FromArgb(0, lightColor)}
                g.FillEllipse(pathBrush, drawRectangle)
            End Using
        End Using

        ' Set the clip boundary  to the edge of the ellipse
        Using gp As GraphicsPath = New GraphicsPath()
            gp.AddEllipse(drawRectangle)
            g.SetClip(gp)
        End Using

        ' Draw the white reflection gradient
        Using ReflectionPath As GraphicsPath = New GraphicsPath()
            Dim whiteRect As Rectangle = New Rectangle(drawRectangle.X - Convert.ToInt32(drawRectangle.Width * 0.15F), drawRectangle.Y - Convert.ToInt32(drawRectangle.Width * 0.15F), Convert.ToInt32(drawRectangle.Width * 0.8F), Convert.ToInt32(drawRectangle.Height * 0.8F))
            ReflectionPath.AddEllipse(whiteRect)
            Using ReflectionPathBrush As PathGradientBrush = New PathGradientBrush(ReflectionPath)
                ReflectionPathBrush.CenterColor = Color.FromArgb(180, 255, 255, 255)
                ReflectionPathBrush.SurroundColors = New Color() {Color.FromArgb(0, 255, 255, 255)}
                g.FillEllipse(ReflectionPathBrush, whiteRect)
            End Using
        End Using

        ' Draw the border
        g.SetClip(Me.ClientRectangle)
        If (m_On) Then
            Using Pen As New Pen(Color.FromArgb(85, Color.Black), 1.0F)
                g.DrawEllipse(Pen, drawRectangle)
            End Using
        End If

    End Sub

    Private Sub m_BlinkTimer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_BlinkTimer.Tick
        If m_On = True Then
            m_On = False
        Else
            m_On = True
        End If
        Me.Invalidate()
    End Sub

#End Region

End Class
